/*******************************************************************************
 * Copyright (c) 2007 University of Oslo.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     University of Oslo - initial API and implementation
 *******************************************************************************/

package com.cea.papyrus.diagram.sequence.sedi.edit.policy;

import org.eclipse.gef.Request;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.commands.CompoundCommand;
import org.eclipse.gef.editpolicies.GraphicalNodeEditPolicy;
import org.eclipse.gef.requests.CreateConnectionRequest;
import org.eclipse.gef.requests.DropRequest;
import org.eclipse.gef.requests.ReconnectRequest;
import org.eclipse.uml2.uml.InteractionOperand;
import org.eclipse.uml2.uml.Message;
import org.eclipse.uml2.uml.NamedElement;

import com.cea.papyrus.core.utils.Debug;
import com.cea.papyrus.diagram.sequence.sedi.edit.SeDiSubpartEditPart;
import com.cea.papyrus.diagram.sequence.sedi.edit.handlers.MessageHandler;
import com.cea.papyrus.diagram.sequence.sedi.edit.handlers.SeparatorHandler;
import com.cea.papyrus.diagram.sequence.sedi.editor.LinkSpecification;
import com.cea.papyrus.diagram.sequence.sedi.editor.MessageSpecification;
import com.cea.papyrus.diagram.sequence.sedi.editor.SeparatorSpecification;
import com.cea.papyrus.diagram.sequence.sedi.figures.SeDiAnchor;
import com.cea.papyrus.diagram.sequence.sedi.model.command.diagram.SetAnchorHintsCommand;
import com.cea.papyrus.diagram.sequence.sedi.model.util.ModelUtil;
import com.cea.papyrus.diagraminterchange2.di2.GraphEdge;

/**
 * This edit part is installed on all edit parts that can be linked (Lifelines,
 * Interaction frames and most interaction fragments).
 * 
 * @author Andreas Limyr
 * @author frankd@ifi.uio.no
 */
public class SeDiNodeEditPolicy extends GraphicalNodeEditPolicy {

    @SuppressWarnings("unchecked")
    @Override
    protected Command getConnectionCreateCommand(CreateConnectionRequest request) {
        final SeDiSubpartEditPart hostEP = (SeDiSubpartEditPart) getHost();
        final SeDiAnchor anchor = (SeDiAnchor) hostEP.getSourceConnectionAnchor(request);
        if (!anchor.acceptConnectionCreate(request))
            return null;

        SetAnchorHintsCommand hintCmd = new SetAnchorHintsCommand();
        hintCmd.setSourceHint(anchor.getTag());
        request.setStartCommand(hintCmd);

        // Save this data for later since it can't be deduced from the
        // request otherwise. Handlers will want to know about the source
        // anchor when they construct commands.
        request.getExtendedData().put("SourceAnchor", anchor);

        return hintCmd;
    }

    @Override
    protected Command getConnectionCompleteCommand(final CreateConnectionRequest request) {
        final SeDiSubpartEditPart<? extends NamedElement> hostEP = (SeDiSubpartEditPart<?>) getHost();
        final SeDiAnchor anchor = (SeDiAnchor) hostEP.getTargetConnectionAnchor(request);
        if (!anchor.acceptConnectionComplete(request))
            return null;

        final CompoundCommand ccmd = new CompoundCommand();

        // Create anchor hint command
        SetAnchorHintsCommand hintCmd = (SetAnchorHintsCommand) request.getStartCommand();
        hintCmd.setTargetHint(anchor.getTag());
        ccmd.add(hintCmd);

        // Delegate the rest of the creation process to the creation handlers
        Command[] cmds = null;

        final LinkSpecification linkSpec = (LinkSpecification) request.getNewObject();
        if (linkSpec instanceof MessageSpecification) {
            cmds = new MessageHandler(this).getCreateCommands(request);
            ccmd.setLabel("Create message");
        } else if (linkSpec instanceof SeparatorSpecification) {
            cmds = new SeparatorHandler(this).getCreateCommands(request);
            ccmd.setLabel("Create Operator separator");
        } else {
        	Debug.log(new Exception("Unexpected type :"+linkSpec));
        }

        return buildCommand(ccmd, cmds);
    }

    @SuppressWarnings("unchecked")
    @Override
    protected Command getReconnectSourceCommand(ReconnectRequest request) {
        final SeDiSubpartEditPart host = (SeDiSubpartEditPart) getHost();
        final SeDiAnchor anchor = (SeDiAnchor) host.getSourceConnectionAnchor(request);
        if (!anchor.acceptReconnectSource(request))
            return null;

        final CompoundCommand ccmd = new CompoundCommand();

        SetAnchorHintsCommand hintCmd = new SetAnchorHintsCommand();
        hintCmd.setSourceHint(anchor.getTag());
        ccmd.add(hintCmd);

        // Delegate the rest of the process to the appropriate handler
        Command[] cmds = null;

        final GraphEdge link = (GraphEdge) request.getConnectionEditPart().getModel();
        if (ModelUtil.<NamedElement> getSemantic(link) instanceof Message) {
            cmds = new MessageHandler(this).getReconnectSourceCommands(request);
            ccmd.setLabel("Move message");
        } else if (ModelUtil.<NamedElement> getSemantic(link) instanceof InteractionOperand) {
            cmds = new SeparatorHandler(this).getReconnectSourceCommands(request);
            ccmd.setLabel("Move separator");
        }

        return buildCommand(ccmd, cmds);
    }

    @SuppressWarnings("unchecked")
    @Override
    protected Command getReconnectTargetCommand(final ReconnectRequest request) {
        final SeDiSubpartEditPart host = (SeDiSubpartEditPart) getHost();
        final SeDiAnchor anchor = (SeDiAnchor) host.getTargetConnectionAnchor(request);
        if (!anchor.acceptReconnectTarget(request))
            return null;

        final CompoundCommand ccmd = new CompoundCommand();

        SetAnchorHintsCommand hintCmd = new SetAnchorHintsCommand();
        hintCmd.setTargetHint(anchor.getTag());
        ccmd.add(hintCmd);

        // Delegate the rest of the process to the appropriate handler
        Command[] cmds = null;

        final GraphEdge link = (GraphEdge) request.getConnectionEditPart().getModel();
        if (ModelUtil.<NamedElement> getSemantic(link) instanceof Message) {
            cmds = new MessageHandler(this).getReconnectTargetCommands(request);
            ccmd.setLabel("Move message");
        } else if (ModelUtil.<NamedElement> getSemantic(link) instanceof InteractionOperand) {
            cmds = new SeparatorHandler(this).getReconnectTargetCommands(request);
            ccmd.setLabel("Move separator");
        }

        return buildCommand(ccmd, cmds);
    }

    @Override
    protected void showTargetConnectionFeedback(DropRequest request) {
        // filter out REQ_RECONNECT_SOURCE requests
        if (!REQ_RECONNECT_SOURCE.equals(((Request) request).getType()))
            super.showTargetConnectionFeedback(request);
    }

    // --- Helper methods ---

    private Command buildCommand(final CompoundCommand ccmd, Command[] cmds) {
        if (cmds != null) {
            for (Command cmd : cmds)
                ccmd.add(cmd);
            return ccmd;
        }
        return null;
    }
}
